#!/usr/bin/python
# jssh.py v0.1
# Author: Marco Gario (marco.gario AT email dOt it)
# Licese: GPL v2

import sys,os
import xmpp
import threading,time
import pexpect

class CommandThread(threading.Thread):
  def __init__(self,conn,mess):
    threading.Thread.__init__(self)
    self.conn=conn
    self.fd_eof=0
    self.cmd=[]
    self.mess=mess
  def Add(self,line):
    self.cmd.append(line)

  def run(self):
    child = pexpect.spawn(self.mess.getBody())
    bcontinue=1
    wait4cmd=0
    while (bcontinue):
      try:
        child.expect('\n',timeout=3)
      except pexpect.TIMEOUT:
        wait4cmd=1
      except pexpect.EOF:
        bcontinue=0

      if (child.before != None) and (child.before!="")and (type(child.before)==type('')):
        msg =unicode(child.before,errors='replace')
        # Remove last \r
        if msg[-1]=='\r':
           msg=msg[:-1]
        if msg!='\n':
           self.conn.send(xmpp.Message(self.mess.getFrom(),msg))
      if (child.after != None) and (child.after!="") and (type(child.after)==type('')):
        msg =unicode(child.after,errors='replace')
        if msg[-1]=='\r':
           msg=msg[:-1]
        if msg!='\n':
           self.conn.send(xmpp.Message(self.mess.getFrom(),msg))
 
      if wait4cmd:
        if (len(self.cmd)>0):
          child.sendline(self.cmd.pop(0))
          bcontinue=1
        else:
         i=0
         while (len(self.cmd)==0) and (i<10): 
           time.sleep(1)
           i=i+1
         if(i==10):
           self.conn.send(xmpp.Message(self.mess.getFrom(),"Command Timeout :("))
           bcontinue=0
         else:
           bcontinue=1
      


  def stop(self):
     fd_eof=0;

class Main:
  def __init__(self,user,server,password):
    self.ACL=['viashino@jabber.org','emdel@jabber.org']
    self.C=None
    self.conn=xmpp.Client(server)#,debug=[])
    conres=self.conn.connect()
    if not conres:
        print "Unable to connect to server %s!"%server
        sys.exit(1)
    if conres<>'tls':
        print "Warning: unable to estabilish secure connection - TLS failed!"
    authres=self.conn.auth(user,password)
    if not authres:
        print "Unable to authorize on %s - check login/password."%server
        sys.exit(1)
    if authres<>'sasl':
        print "Warning: unable to perform SASL auth os %s. Old authentication method used!"%server
    self.conn.RegisterHandler('message',self.messageCB)
    self.conn.sendInitPresence()
    self.GoOn()

  def IsAuthorized(self,user):
    if xmpp.protocol.JID(user).getStripped() in self.ACL:
       return 1
    return 0
  
  def messageCB(self,conn,mess):
    text=mess.getBody()
    user=mess.getFrom()
    if (mess.getType()=='chat') and not(text is None):
      if self.IsAuthorized(user):

         ## Define default commands ##
         if text[0]=='*':
            if text[1:]=='close':
               sys.exit(0)
            elif text[1:]=='ping':
               conn.send(xmpp.Message(mess.getFrom(),'PONG'))

         ## run command locally ##
         elif (self.C==None) or not(self.C.isAlive()):
           print "creating Thread"
           self.C=CommandThread(self.conn,mess)
           self.C.start()
         else:
           # If we are already running a program, lets add an input line
           self.C.Add(text)


  def StepOn(self):
    try:
        self.conn.Process(1)
    except KeyboardInterrupt: return 0
    return 1

  def GoOn(self):
    while self.StepOn(): pass

if len(sys.argv)<3:
    print "Usage: jabsh.py username@server.net password"
else:
    jid=xmpp.JID(sys.argv[1])
    user,server,password=jid.getNode(),jid.getDomain(),sys.argv[2]
    Main(user,server,password)
